﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once
#pragma managed(push,off)
#include "ApiIEventHandler.h"
#include "ApiObjectCreatorMap.h"
#pragma managed(pop)

class InternalAPITypeConverter {
public:
    template<typename NT, typename MT>
    static MT^ ToManaged(NT* pNativeObj) {
        MT^ managedObj = nullptr;
        if (nullptr == pNativeObj) {
            managedObj = nullptr;
        }
        else
        {
            auto&& creator = gdmp::api::APIObjectCreatorMap::get(pNativeObj->ObjectKind());
            if (nullptr == creator) {
                managedObj = gcnew MT(pNativeObj);
            }
            else {
                System::Runtime::InteropServices::GCHandle h = System::Runtime::InteropServices::GCHandle::FromIntPtr(System::IntPtr(creator(pNativeObj)));
                managedObj = static_cast<MT^>(h.Target);
                h.Free();
            }
        }

        return managedObj;
    }
};

class APIExceptionConverter {
public:
    static System::Exception^ ToManaged(const std::exception& e) {
        auto&& creator = gdmp::api::APIObjectCreatorMap::get(typeid(e).name());
        if (nullptr == creator) {
            return gcnew System::Exception(gcnew System::String(e.what()));
        }
        System::Runtime::InteropServices::GCHandle h = System::Runtime::InteropServices::GCHandle::FromIntPtr(System::IntPtr(creator((void*)(&e))));
        System::Exception^ managedObj = static_cast<System::Exception^>(h.Target);
        h.Free();

        return managedObj;
    }
};

template<typename NT, typename MT>
class InternalAPIEventHandler final : public gdmp::api::IEventHandler {
public:
    InternalAPIEventHandler(System::Object^ eventHost, System::EventHandler<MT^>^ handler)
        : m_eventHost(eventHost), m_delegate(handler)
    {}
    virtual void On(gdmp::api::APIEventArgs* e) override
    {
        try
        {
            MT^ managedEvtAgrs = InternalAPITypeConverter::ToManaged<NT, MT>(dynamic_cast<NT*>(e));
            m_delegate->DynamicInvoke(m_eventHost, managedEvtAgrs);
        }
        catch (...)
        {
        }
    }
private:
    gcroot<System::Object^> m_eventHost;
    gcroot<System::EventHandler<MT^>^> m_delegate;
};

class APIString
{
public:
    static std::wstring ToWString(System::String^ str) {
        if (System::String::IsNullOrEmpty(str))return {};
        System::IntPtr ptr = System::Runtime::InteropServices::Marshal::StringToHGlobalUni(str);
        const wchar_t* chars = static_cast<const wchar_t*>(ptr.ToPointer());
        std::wstring wstr(chars);
        System::Runtime::InteropServices::Marshal::FreeHGlobal(ptr);
        return std::move(wstr);
    }
};

#define REGISTER_APIOBJECT_CREATOR(NativeType,ManagedType,ManagedNS) \
namespace gdmp{namespace api{\
APIObjectCreatorMap s_##ManagedType(NativeType::ClassType(),  [](void* pNativeObj){return System::Runtime::InteropServices::GCHandle::ToIntPtr(System::Runtime::InteropServices::GCHandle::Alloc(gcnew ManagedNS::ManagedType(static_cast<NativeType*>(pNativeObj)))).ToPointer(); }); \
}}
#define REGISTER_APIEXCEPTION_CREATOR(NException,MException,ManagedNS) \
namespace gdmp{namespace api{\
APIObjectCreatorMap s_##MException(typeid(NException).name(), [](void* pNativeObj){return System::Runtime::InteropServices::GCHandle::ToIntPtr(System::Runtime::InteropServices::GCHandle::Alloc(gcnew ManagedNS::MException(gcnew System::String((static_cast<std::exception*>(pNativeObj))->what())))).ToPointer();});\
}}

#define TEST_ARGUMENTNULL(arg,name)\
if(nullptr==arg) throw gcnew System::ArgumentNullException(name);
